#pragma once

// C
#include <cassert>
#include <cstring>
// C++
#include <algorithm>
#include <memory>
#include <span>
#include <string_view>
#include <vector>
namespace fastrpc::io::detail {

class StreamBuffer {
public:
    // 构造函数，初始化一个指定大小的缓冲区
    explicit StreamBuffer(std::size_t size) : buf_(size) {}

    // 定义StreamBuffer的智能指针类型
    using s_ptr = std::shared_ptr<StreamBuffer>;

public:
    // 重置数据：将剩余的可读数据拷贝到缓冲区的起始位置，并重置读写指针
    void reset_data() noexcept {
        auto len = r_remaining();                     // 获取剩余的可读数据长度
        std::copy(r_begin(), r_end(), buf_.begin());  // 拷贝数据到缓冲区起始位置
        r_pos_ = 0;                                   // 重置读指针
        w_pos_ = len;                                 // 设置写指针为已读数据的长度
    }

    // 禁用缓冲区，清空缓冲区的数据
    void disable() noexcept {
        std::vector<char>().swap(buf_);  // 用空的vector交换，释放内存
    }

    // 重置读写指针
    void reset_pos() noexcept {
        r_pos_ = w_pos_ = 0;  // 读指针和写指针都设置为0
    }

    // 增加读指针，向前移动n个字节
    void r_increase(std::size_t n) noexcept {
        r_pos_ += n;               // 增加读指针
        assert(r_pos_ <= w_pos_);  // 确保读指针不会超过写指针
    }

    // 获取剩余可读数据的长度
    [[nodiscard]]
    auto r_remaining() const noexcept -> std::size_t {
        return w_pos_ - r_pos_;  // 返回剩余可读的数据长度
    }

    // 获取当前读指针的起始位置（const_iterator）
    [[nodiscard]]
    auto r_begin() const noexcept -> std::vector<char>::const_iterator {
        return buf_.begin() + r_pos_;  // 返回读指针位置
    }

    // 获取当前读指针的结束位置（const_iterator）
    [[nodiscard]]
    auto r_end() const noexcept -> const std::vector<char>::const_iterator {
        return r_begin() + r_remaining();  // 返回剩余可读数据的结束位置
    }

    // 返回当前可读数据的slice
    [[nodiscard]]
    auto r_slice() const noexcept -> std::span<const char> {
        return {r_begin(), r_end()};  // 返回当前可读数据的span
    }

    // 增加写指针，向前移动n个字节
    void w_increase(std::size_t n) noexcept {
        w_pos_ += n;               // 增加写指针
        assert(r_pos_ <= w_pos_);  // 确保写指针不会超过读指针
    }

    // 获取剩余可写数据的长度
    [[nodiscard]]
    auto w_remaining() const noexcept -> std::size_t {
        return buf_.size() - w_pos_;  // 返回剩余可写的数据长度
    }

    // 获取当前写指针的起始位置（iterator）
    [[nodiscard]]
    auto w_begin() noexcept -> std::vector<char>::iterator {
        return buf_.begin() + w_pos_;  // 返回写指针位置
    }

    // 获取当前写指针的结束位置（iterator）
    [[nodiscard]]
    auto w_end() noexcept -> std::vector<char>::iterator {
        return w_begin() + w_remaining();  // 返回剩余可写数据的结束位置
    }

    // 返回当前可写数据的slice
    [[nodiscard]]
    auto w_slice() noexcept -> std::span<char> {
        return {w_begin(), w_end()};  // 返回当前可写数据的span
    }

    // 判断缓冲区是否为空（即没有可读数据）
    [[nodiscard]]
    auto empty() const noexcept -> bool {
        return r_pos_ == w_pos_;  // 如果读指针等于写指针，说明缓冲区为空
    }

    // 获取缓冲区的容量
    [[nodiscard]]
    auto capacity() const noexcept -> std::size_t {
        return buf_.size();  // 返回缓冲区的大小
    }

    // 将数据从缓冲区写入目标缓冲区（dst_buf），并更新读指针
    [[nodiscard]]
    // data : buffer -> user
    auto write_to(std::span<char> dst_buf) noexcept -> std::size_t {
        auto len = std::min(r_remaining(), dst_buf.size_bytes());  // 计算可读取的最大长度
        std::copy_n(r_begin(), len, dst_buf.begin());              // 将数据从缓冲区复制到目标缓冲区
        r_increase(len);                                           // 增加读指针
        if (r_pos_ == w_pos_) {
            reset_pos();  // 如果读指针等于写指针，重置读写指针
        }
        return len;  // 返回实际写入的字节数
    }

    // 从源缓冲区（src_buf）读取数据到缓冲区，并更新写指针
    [[nodiscard]]
    // data : user -> buffer
    auto read_from(std::span<const char> src_buf) noexcept -> std::size_t {
        auto len = std::min(w_remaining(), src_buf.size_bytes());  // 计算可写入的最大长度
        std::copy_n(src_buf.begin(), len, w_begin());              // 将数据从源缓冲区复制到缓冲区
        w_increase(len);                                           // 增加写指针
        return len;                                                // 返回实际读取的字节数
    }

    // 查找指定的标志字符串并返回相应的数据切片
    [[nodiscard]]
    auto find_flag_and_return_slice(std::string_view end_str) noexcept -> std::span<const char> {
        auto pos = std::string_view{r_slice()}.find(end_str);  // 在可读数据中查找标志字符串
        if (pos == std::string_view::npos) {
            return {};  // 如果没有找到标志字符串，返回空span
        } else {
            return {r_begin(), pos + end_str.size()};  // 返回从缓冲区开始到标志字符串结束的数据切片
        }
    }

    // 查找指定的结束字符并返回相应的数据切片
    [[nodiscard]]
    auto find_flag_and_return_slice(char end_char) noexcept -> std::span<const char> {
        auto pos = std::string_view{r_slice()}.find(end_char);  // 在可读数据中查找结束字符
        if (pos == std::string_view::npos) {
            return {};  // 如果没有找到结束字符，返回空span
        } else {
            return {r_begin(), pos + 1};  // 返回从缓冲区开始到结束字符的位置的数据切片
        }
    }

public:
    // 默认缓冲区大小：8KB
    static constexpr std::size_t DEFAULT_BUF_SIZE{8 * 1024};

private:
    std::vector<char> buf_;       // 存储缓冲区数据的vector
    std::size_t       r_pos_{0};  // 读指针位置
    std::size_t       w_pos_{0};  // 写指针位置
};

}  // namespace fastrpc::io::detail
